package parseur_graphique;

import java.io.IOException;

import java.lang.reflect.InvocationTargetException;

import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.LocatorImpl;
import org.xml.sax.helpers.XMLReaderFactory;

import projet.*;
import exceptions.*;

public class SimpleContentHandler implements ContentHandler {

	static private Workshop w;
    static private Object curr;
    java.lang.reflect.Method m;


	// Function reads a given XML file and fills given Workshop w with data from file
	//      (workshop name, providers, operations...)
    public static void fillWorkshopFromXMLFile(String fileName, Workshop myWorkshop) throws SAXException, IOException    {
    	w = myWorkshop;
    	XMLReader saxReader = XMLReaderFactory.createXMLReader();
    	saxReader.setContentHandler(new SimpleContentHandler());
    	saxReader.parse(fileName);
    }
    public SimpleContentHandler() {
    	super();
        new LocatorImpl();
    }

    /**
     * Definition du locator qui permet a tout moment pendant l'analyse, de localiser
     * le traitement dans le flux. Le locator par defaut indique, par exemple, le numero
     * de ligne et le numero de caractere sur la ligne.
     * @author smeric
     * @param value le locator a utiliser.
     * @see org.xml.sax.ContentHandler#setDocumentLocator(org.xml.sax.Locator)
     */
    public void setDocumentLocator(Locator value) {
    }

    /**
     * Evenement envoye au demarrage du parse du flux xml.
     * @throws SAXException en cas de probleme quelquonque ne permettant pas de
     * se lancer dans l'analyse du document.
     * @see org.xml.sax.ContentHandler#startDocument()
     */
    public void startDocument() throws SAXException {
            // System.out.println("Debut de l'analyse du document");
            curr = w;
    }

    /**
     * Evenement envoye a la fin de l'analyse du flux xml.
     * @throws SAXException en cas de probleme quelquonque ne permettant pas de
     * considerer l'analyse du document comme etant complete.
     * @see org.xml.sax.ContentHandler#endDocument()
     */
    public void endDocument() throws SAXException {
            //System.out.println("Fin de l'analyse du document" );
    }

    /**
     * Debut de traitement dans un espace de nommage.
     * @param prefixe utilise pour cet espace de nommage dans cette partie de l'arborescence.
     * @param URI de l'espace de nommage.
     * @see org.xml.sax.ContentHandler#startPrefixMapping(java.lang.String, java.lang.String)
     */
    public void startPrefixMapping(String prefix, String URI) throws SAXException {
            //System.out.println("Traitement de l'espace de nommage : " + URI + ", prefixe choisi : " + prefix);
    }

    /**
     * Fin de traitement de l'espace de nommage.
     * @param prefixe le prefixe choisi a l'ouverture du traitement de l'espace nommage.
     * @see org.xml.sax.ContentHandler#endPrefixMapping(java.lang.String)
     */
    public void endPrefixMapping(String prefix) throws SAXException {
            //System.out.println("Fin de traitement de l'espace de nommage : " + prefix);
    }

    /**
     * Evenement recu a chaque fois que l'analyseur rencontre une balise xml ouvrante.
     * @param nameSpaceURI l'url de l'espace de nommage.
     * @param localName le nom local de la balise.
     * @param rawName nom de la balise en version 1.0 <code>nameSpaceURI + ":" + localName</code>
     * @throws SAXException si la balise ne correspond pas a ce qui est attendu,
     * comme par exemple non respect d'une dtd.
     * @see org.xml.sax.ContentHandler#startElement(java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes)
     */
    public void startElement(String nameSpaceURI, String localName, String rawName, Attributes attributs) throws SAXException {
          //  System.out.println("Ouverture de la balise : " + localName);
            if (localName.equals("Workshop")) return;

            // recherche d'un setter
            if (localName.charAt(0) >= 'a') {
                    java.lang.reflect.Method[] meths = curr.getClass().getMethods();
                    String setter = "set"+(""+localName.charAt(0)).toUpperCase()+localName.substring(1);
                    String adder = "add"+(""+localName.charAt(0)).toUpperCase()+localName.substring(1);
                    for (int i = 0; i < meths.length; i++) {
                            if (meths[i].getName().equals(setter) || meths[i].getName().equals(adder)) {
                         	   m = meths[i];
                         	   return;
                            }
                    }
                    throw new SAXException("startDocument() exception: unknown attribute tag:"+localName+" in class "+curr.getClass().getName());
            }
            // sinon recherche d'une classe
            try {
                    Class c = Class.forName("projet."+localName);
                    Object o = c.newInstance();
                    java.lang.reflect.Method[] meths = w.getClass().getMethods();
                    // recherche de la méthode d'ajout des instances à l'atelier
                    String adder = "add"+localName;
                    for (int i = 0; i < meths.length; i++) {
                            if (meths[i].getName().equals(adder)) {
                                    meths[i].invoke(w, o);
                                            m = null;
                                            curr = o;
                                    return;
                            }
                    }
                    throw new SAXException("unknown attribute tag:"+localName+" in class "+curr.getClass().getName());

                    } catch (InvocationTargetException e) {
                            throw new SAXException("unexpected subclass:"+localName);
                    } catch (ClassNotFoundException e) {
                            throw new SAXException("unknown tag:"+localName);
                    } catch (InstantiationException e) {
                            throw new SAXException("class not instantiable:"+localName);
                    } catch (IllegalAccessException e) {
                            throw new SAXException("hidden class:"+localName);
                    }
    }



    /**
     * Evenement recu a chaque fermeture de balise.
     * @see org.xml.sax.ContentHandler#endElement(java.lang.String, java.lang.String, java.lang.String)
     */
    public void endElement(String nameSpaceURI, String localName, String rawName) throws SAXException {
         //   System.out.println("Fermeture de la balise : " + localName);
            if (m == null && curr != w) curr = w; // retour au niveau racine
            if (m != null) m = null; // retour au niveau classe
    }

    /**
     * Evenement recu a chaque fois que l'analyseur rencontre des caracteres (entre
     * deux balises).
     * @param ch les caracteres proprement dits.
     * @param start le rang du premier caractere a traiter effectivement.
     * @param end le rang du dernier caractere a traiter effectivement
     * @see org.xml.sax.ContentHandler#characters(char[], int, int)
     */
    public void characters(char[] ch, int start, int end) throws SAXException {
                    while (end > 0 && ch[start] <= 32) { end--; start++;}
                    String s = new String(ch, start, end);
                    // System.out.println("#PCDATA (" + (s.length())+"):"+s);
                    if (s.equals("")) return;
                    if (m == null)
                    throw new SAXException("startDocument() exception: invalid data field:"+s);
                    try {
                            Class ty = m.getParameterTypes()[0];

                            if (ty.getName().equals("java.lang.String"))
                                    m.invoke(curr, s);
                            else if (ty.getName().equals("float") || ty.getName().equals("java.lang.Float"))
                                    m.invoke(curr, new Float(s));
                            else
                    throw new SAXException("exception: invalid type:"+ty.getName()+" for "+m.getName());
                    }
                    catch (Exception e) {
                    e.printStackTrace();
                    throw new SAXException("exception: invalid access to field:"+s);
                    }

    }

    /**
     * Recu chaque fois que des caracteres d'espacement peuvent etre ignores au sens de
     * XML. C'est a dire que cet evenement est envoye pour plusieurs espaces se succedant,
     * les tabulations, et les retours chariot se succedants ainsi que toute combinaison de ces
     * trois types d'occurrence.
     * @param ch les caracteres proprement dits.
     * @param start le rang du premier caractere a traiter effectivement.
     * @param end le rang du dernier caractere a traiter effectivement
     * @see org.xml.sax.ContentHandler#ignorableWhitespace(char[], int, int)
     */
    public void ignorableWhitespace(char[] ch, int start, int end) throws SAXException {
            //System.out.println("espaces inutiles rencontres : ..." + new String(ch, start, end) +  "...");
    }

    /**
     * Rencontre une instruction de fonctionnement.
     * @param target la cible de l'instruction de fonctionnement.
     * @param data les valeurs associees a cette cible. En general, elle se presente sous la forme
     * d'une serie de paires nom/valeur.
     * @see org.xml.sax.ContentHandler#processingInstruction(java.lang.String, java.lang.String)
     */
    public void processingInstruction(String target, String data) throws SAXException {
            //System.out.println("Instruction de fonctionnement : " + target);
            //System.out.println("  dont les arguments sont : " + data);
    }

    /**
     * Recu a chaque fois qu'une balise est evitee dans le traitement a cause d'un
     * probleme non bloque par le parser. Pour ma part je ne pense pas que vous
     * en ayez besoin dans vos traitements.
     * @see org.xml.sax.ContentHandler#skippedEntity(java.lang.String)
     */
    public void skippedEntity(String arg0) throws SAXException {
            // Je ne fais rien, ce qui se passe n'est pas franchement normal.
            // Pour eviter cet evenement, le mieux est quand meme de specifier une dtd pour vos
            // documents xml et de les faire valider par votre parser.
    }

}